﻿using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Data.Objects;
using System.Transactions;
using System.Data;

namespace FrameworkLib.Facades
{
    public abstract class FacadeBase<Context> where Context : ObjectContext, new()
    {
        private Exception m_lastExceptionOccurred = null;

        public Exception LastExceptionOccurred
        {
            get { return m_lastExceptionOccurred; }
            set { m_lastExceptionOccurred = value; }
        }

        private static ConcurrentDictionary<Type, ObjectContext> m_contexts = new ConcurrentDictionary<Type, ObjectContext>();
        //private static Dictionary<Type, ObjectContext> m_contexts = new Dictionary<Type, ObjectContext>();
        int m_pageSize;

        public FacadeBase()
        {
        }

        //public static Context GetContext()
        //{
        //    Context m_c = null;

        //    if (m_contexts.ContainsKey(typeof(Context)))
        //    {
        //        m_c = (Context)m_contexts[typeof(Context)];
        //    }
        //    else
        //    {
        //        m_c = new Context();

        //        //m_contexts.Add(typeof(Context), m_c);
        //        m_contexts.AddOrUpdate(typeof(Context), m_c, (k, v) => v);
        //    }

        //    if (m_c.Connection.State == System.Data.ConnectionState.Closed) m_c.Connection.Open();

        //    return m_c;
        //}

        public Context GetContext()
        {
            Context m_c = null;

            if (m_contexts.ContainsKey(typeof(Context)))
            {
                m_c = (Context)m_contexts[typeof(Context)];
            }
            else
            {
                m_c = new Context();

                //m_contexts.Add(typeof(Context), m_c);
                m_contexts.AddOrUpdate(typeof(Context), m_c, (k, v) => v);
            }

            if (m_c.Connection.State == System.Data.ConnectionState.Closed) m_c.Connection.Open();

            return m_c;
        }

        public Context GetContext(string connection)
        {
            Context m_c = null;

            if (m_contexts.ContainsKey(typeof(Context)))
            {
                m_c = (Context)m_contexts[typeof(Context)];
            }
            else
            {
                m_c = (Context)Activator.CreateInstance(typeof(Context), connection);

                //m_contexts.Add(typeof(Context), m_c);
                m_contexts.AddOrUpdate(typeof(Context), m_c, (k, v) => v);
            }

            if (m_c.Connection.State == System.Data.ConnectionState.Closed) m_c.Connection.Open();

            return m_c;
        }

        public void RunAsync<T>(Func<T> action, BackgroundWorkerCallbackBase.Callback callback)
        {
            BackGroundWorkerWrapper<T> p = new BackGroundWorkerWrapper<T>(action, callback);
            p.RunWorkerAsync();
        }

        public void RunAsync<T>(Func<T> action, BackgroundWorkerCallbackBase.Callback callback, params object[] argument)
        {
            BackGroundWorkerWrapper<T> p = new BackGroundWorkerWrapper<T>(action, callback);
            p.RunWorkerAsync(argument);
        }

        public void Transact(Action action)
        {
            using (TransactionScope transaction = new TransactionScope())
            {
                action();
                transaction.Complete();
            }
        }

        public void Transact(Action action, TransactionScopeOption scopeOption)
        {
            using (TransactionScope transaction = new TransactionScope(scopeOption))
            {
                action();
                transaction.Complete();
            }
        }

        public void ManageConcurrency(Action action, params bool[] returnValue)
        {
            try
            {
                action();
            }
            catch (OptimisticConcurrencyException ocexp)
            {
                System.Data.Objects.DataClasses.EntityObject oo = (System.Data.Objects.DataClasses.EntityObject)ocexp.StateEntries[0].Entity;

                string msg = string.Format("- {0} - ATTENZIONE! I dati che stai per salvare sono stati modificati da un altro utente.", "ciccio");

                System.Windows.Forms.MessageBox.Show(msg);
                //{
                //    // Resolve the concurrency conflict by refreshing the 
                //    // object context before re-saving changes. 
                //    //GetContext().Refresh(RefreshMode.StoreWins, ocexp.StateEntries[0].Entity);

                //    // Save changes.
                //    //GetContext().SaveChanges();

                //    //Console.WriteLine("OptimisticConcurrencyException " + "handled and changes saved");
                //}

                returnValue.SetValue(false, 0);
            }
        }
    }
}
